#version 330

in vec2 fs_Texcoord;

uniform sampler2D u_depthTX;  // Set as the depth buffer texture to avoid unpacking
uniform sampler2D u_normalTX;
uniform sampler2D u_outTX;

uniform float u_Near;
uniform float u_Far;

out vec4 out_Edge;
out vec4 out_smallHorizontalBlur;
out vec4 out_largeHorizontalBlur;

uniform int u_screenWidth;
uniform int u_screenHeight;

#define BLUR_MULT .75f

vec2 unpack4x8To2Float(in vec4 val) {
	const vec2 unshift = vec2(1.0f/256.0f, 1.0f);
	return vec2(dot(val.xy, unshift), dot(val.zw, unshift));
}

// Code from : http://aras-p.info/texts/CompactNormalStorage.html
vec3 unpackNormal(in vec2 encNorm) {
#ifdef DEBUG
	if(encNorm.x < .000001f && encNorm.y < .00000001)
		return vec3(.0f, .0f, .0f);
#endif

	encNorm = encNorm*4.0f - 2.0f;
	float f = dot(encNorm, encNorm);
	float g = sqrt(1.0f -.25f*f);
	return vec3(encNorm*g,1.0f - .5f*f);
}

float linearizeDepth(float exp_depth) {
    return	(2 * u_Near) / (u_Far + u_Near -  exp_depth * (u_Far - u_Near)); 
}

#define NUM_BLUR_SAMPLES 5
const float blurWeights[NUM_BLUR_SAMPLES] = float[] (.0f, .2f, .6f, .2f, .0f);


// Edge detection inspired by:
// http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=39340&sid=116487f58cadae3e747e16d873738282
void main(void) {
	float depth = linearizeDepth(texture(u_depthTX, fs_Texcoord).x);
	vec3 normal = unpackNormal(unpack4x8To2Float(texture(u_normalTX, fs_Texcoord)));
	
	// Sample the surrounding depths
	float dd_depth = depth - linearizeDepth(textureOffset(u_depthTX, fs_Texcoord, ivec2(-1,-1)).x);
	dd_depth -= depth - linearizeDepth(textureOffset(u_depthTX, fs_Texcoord, ivec2(-1, 0)).x);
	dd_depth -= depth - linearizeDepth(textureOffset(u_depthTX, fs_Texcoord, ivec2(-1, 1)).x);
	dd_depth -= depth - linearizeDepth(textureOffset(u_depthTX, fs_Texcoord, ivec2(0, -1)).x);
	dd_depth -= depth - linearizeDepth(textureOffset(u_depthTX, fs_Texcoord, ivec2(0, 1)).x);
	dd_depth -= depth - linearizeDepth(textureOffset(u_depthTX, fs_Texcoord, ivec2(1, -1)).x);
	dd_depth -= depth - linearizeDepth(textureOffset(u_depthTX, fs_Texcoord, ivec2(1, 0)).x);
	dd_depth -= depth - linearizeDepth(textureOffset(u_depthTX, fs_Texcoord, ivec2(1, 1)).x);
	
	// Sample the surrounding normals
	float normalDiff = .0f;
	normalDiff += 1.0f - dot(normal,unpackNormal(unpack4x8To2Float(textureOffset(u_normalTX, fs_Texcoord, ivec2(-1,-1)))));
	normalDiff += 1.0f - dot(normal,unpackNormal(unpack4x8To2Float(textureOffset(u_normalTX, fs_Texcoord, ivec2(-1,0)))));
	normalDiff += 1.0f - dot(normal,unpackNormal(unpack4x8To2Float(textureOffset(u_normalTX, fs_Texcoord, ivec2(-1,1)))));
	normalDiff += 1.0f - dot(normal,unpackNormal(unpack4x8To2Float(textureOffset(u_normalTX, fs_Texcoord, ivec2(0,-1)))));
	normalDiff += 1.0f - dot(normal,unpackNormal(unpack4x8To2Float(textureOffset(u_normalTX, fs_Texcoord, ivec2(0,1)))));
	normalDiff += 1.0f - dot(normal,unpackNormal(unpack4x8To2Float(textureOffset(u_normalTX, fs_Texcoord, ivec2(1,-1)))));
	normalDiff += 1.0f - dot(normal,unpackNormal(unpack4x8To2Float(textureOffset(u_normalTX, fs_Texcoord, ivec2(1,0)))));
	normalDiff += 1.0f - dot(normal,unpackNormal(unpack4x8To2Float(textureOffset(u_normalTX, fs_Texcoord, ivec2(1,1)))));
	
	if(abs(dd_depth) > .35f || normalDiff > 2.75)
		out_Edge = vec4(1.0f,1.0f,1.0f,1.0f);
	else
		out_Edge = vec4(.0f,.0f,.0f,0.0f);
		
	vec2 offset = vec2(1.0f/u_screenWidth, .0f);
	
	float d = 1 - depth;
	
	vec4 blurReads = 
		texture(u_outTX, fs_Texcoord - d*BLUR_MULT*6*offset) +
		texture(u_outTX, fs_Texcoord - d*BLUR_MULT*4*offset) +
		texture(u_outTX, fs_Texcoord - d*BLUR_MULT*2*offset) +
		texture(u_outTX, fs_Texcoord) +
		texture(u_outTX, fs_Texcoord + d*BLUR_MULT*2*offset) +
		texture(u_outTX, fs_Texcoord + d*BLUR_MULT*4*offset) +
		texture(u_outTX, fs_Texcoord + d*BLUR_MULT*6*offset);
		
	out_smallHorizontalBlur = (1.0f/7.0f)*blurReads;
		
	blurReads +=
		texture(u_outTX, fs_Texcoord - d*BLUR_MULT*12*offset) +
		texture(u_outTX, fs_Texcoord - d*BLUR_MULT*10*offset) +
		texture(u_outTX, fs_Texcoord - d*BLUR_MULT*8*offset) +
		texture(u_outTX, fs_Texcoord + d*BLUR_MULT*8*offset) +
		texture(u_outTX, fs_Texcoord + d*BLUR_MULT*10*offset) +
		texture(u_outTX, fs_Texcoord + d*BLUR_MULT*12*offset);
	
/*	
	vec4 blurReads = 
		textureOffset(u_outTX, fs_Texcoord, ivec2(-3,0)) +
		textureOffset(u_outTX, fs_Texcoord, ivec2(-2,0)) +
		textureOffset(u_outTX, fs_Texcoord, ivec2(-1,0)) +
		textureOffset(u_outTX, fs_Texcoord, ivec2(0,0)) +
		textureOffset(u_outTX, fs_Texcoord, ivec2(1,0)) +
		textureOffset(u_outTX, fs_Texcoord, ivec2(2,0)) +
		textureOffset(u_outTX, fs_Texcoord, ivec2(3,0));
		
	out_smallHorizontalBlur = (1.0f/7.0f)*blurReads;
		
	blurReads +=
		textureOffset(u_outTX, fs_Texcoord, ivec2(-7,0)) +
		textureOffset(u_outTX, fs_Texcoord, ivec2(-6,0)) +
		textureOffset(u_outTX, fs_Texcoord, ivec2(-4,0)) +
		textureOffset(u_outTX, fs_Texcoord, ivec2(4,0)) +
		textureOffset(u_outTX, fs_Texcoord, ivec2(6,0)) +
		textureOffset(u_outTX, fs_Texcoord, ivec2(7,0));
*/
		
	out_largeHorizontalBlur = (1.0f/13.0f)*blurReads;
}